__author__ = 'YT'

import pygame as pg
from .. import tool
from .. import constants as c

class Map():
    # 定义构造函数，初始化地图的宽度、高度和网格
    def __init__(self, width, height, grid):
        # 地图的宽度
        self.width = width
        # 地图的高度
        self.height = height
        # 地图的背景，用0表示
        self.bg_map = [[0 for x in range(self.width)] for y in range(self.height)]
        # 地图上的实体，用None表示
        self.entity_map = [[None for x in range(self.width)] for y in range(self.height)]
        # 当前活动的实体
        self.active_entity = None
        # 选择的实体
        self.select = None
        # 设置地图图像
        self.setupMapImage(grid)
        # 设置鼠标图像
        self.setupMouseImage()

    def setupMapImage(self, grid):
        # 初始化地图图片
        self.grid_map = [[0 for x in range(self.width)] for y in range(self.height)]
        # 如果grid不为空
        if grid is not None:
            # 遍历grid中的每一个数据
            for data in grid:
                # 获取x, y, type
                x, y, type = data['x'], data['y'], data['type']
                # 将type赋值给grid_map
                self.grid_map[y][x] = type
        # 创建地图图片
        self.map_image = pg.Surface((self.width * c.REC_SIZE, self.height * c.REC_SIZE)).convert()
        # 获取地图图片的矩形
        self.rect = self.map_image.get_rect()
        # 设置地图图片的x, y
        self.rect.x = 0
        self.rect.y = 0
        # 遍历地图的每一个点
        for y in range(self.height):
            for x in range(self.width):
                # 获取type
                type = self.grid_map[y][x]
                # 如果type不为空
                if type != c.MAP_EMPTY:
                    # 如果使用六边形地图
                    if c.MAP_HEXAGON:
                        # 获取六边形地图的坐标
                        base_x, base_y = tool.getHexMapPos(x, y)
                        # 将图片粘贴到地图图片上
                        self.map_image.blit(tool.GRID[type], (base_x, base_y))
                    # 如果使用矩形地图
                    else:
                        # 将图片粘贴到地图图片上
                        self.map_image.blit(tool.GRID[type], (x * c.REC_SIZE, y * c.REC_SIZE))
        # 设置地图图片的背景色
        self.map_image.set_colorkey(c.BLACK)

    def setupMouseImage(self):
        # 创建一个空列表，用于存放鼠标图片
        self.mouse_frames = []
        # 定义鼠标图片的位置和大小
        frame_rect = (0, 0, 25, 27)
        # 从图片中获取鼠标图片
        self.mouse_image = tool.get_image(tool.GFX[c.MOUSE], *frame_rect, c.BLACK, 1)
        # 获取鼠标图片的矩形
        self.mouse_rect = self.mouse_image.get_rect()
        # 设置鼠标不可见
        pg.mouse.set_visible(False)

    def isValid(self, map_x, map_y):
        # 如果地图是六边形
        if c.MAP_HEXAGON:
            # 如果map_y是偶数
            if map_y % 2 == 0:
                # 最大x坐标是地图宽度
                max_x = self.width
            else:
                # 最大x坐标是地图宽度减1
                max_x = self.width - 1
        else:
            # 如果地图不是六边形，最大x坐标是地图宽度
            max_x = self.width
        # 如果map_x小于0，大于等于最大x坐标，map_y小于0，大于等于地图高度，则返回False
        if (map_x < 0 or map_x >= max_x or
            map_y < 0 or map_y >= self.height):
            return False
        # 否则返回True
        return True
    
    def isMovable(self, map_x, map_y):
        # 判断指定位置的实体是否为空，且地图格子不是石头
        return (self.entity_map[map_y][map_x] == None and
                self.grid_map[map_y][map_x] != c.MAP_STONE)

    def getMapIndex(self, x, y):
        # 如果地图是六边形
        if c.MAP_HEXAGON:
            # 使用tool模块中的getHexMapIndex函数获取六边形地图的索引
            return tool.getHexMapIndex(x, y)
        # 如果地图是矩形
        else:
            # 计算x和y在地图上的索引
            return (x//c.REC_SIZE, y//c.REC_SIZE)

    def getDistance(self, x1, y1, map_x2, map_y2):
        # 如果地图是六边形
        if c.MAP_HEXAGON:
            # 将map_x2, map_y2转换为六边形坐标
            x2, y2 = tool.getHexMapPos(map_x2, map_y2)
            # 将x2, y2平移到六边形中心
            x2 += c.HEX_X_SIZE // 2
            y2 += c.HEX_Y_SIZE // 2
            # 计算距离
            distance = (abs(x1 - x2) + abs(y1 - y2))
        else:
            # 将x1, y1转换为地图坐标
            map_x1, map_y1 = self.getMapIndex(x1, y1)
            # 将map_x2, map_y2转换为实际坐标
            x2 = map_x2 * c.REC_SIZE + c.REC_SIZE//2
            y2 = map_y2 * c.REC_SIZE + c.REC_SIZE//2
            # 计算距离
            distance = (abs(x1 - x2) + abs(y1 - y2))
            # 如果地图坐标不同，则减去c.REC_SIZE//2
            if map_x1 != map_x2 and map_y1 != map_y2:
               distance -= c.REC_SIZE//2
        # 返回距离
        return distance

    def checkMouseClick(self, x, y):
        # 如果active_entity为空，则返回False
        if self.active_entity is None:
            return False

        # 获取鼠标点击的地图索引
        map_x, map_y = self.getMapIndex(x, y)
        # 如果地图索引无效，则返回False
        if not self.isValid(map_x, map_y):
            return False

        # 获取地图上该索引的实体
        entity = self.entity_map[map_y][map_x]
        # 如果实体为空或者实体等于active_entity，并且active_entity在范围内
        if ((entity is None or entity == self.active_entity) and
            self.active_entity.inRange(self, map_x, map_y)):
            # 设置active_entity的目的地
            self.active_entity.setDestination(map_x, map_y)
            return True
        # 如果实体不为空
        elif entity is not None:
            # 如果active_entity是远程实体
            if self.active_entity.isRemote():
                # 设置active_entity的目标实体
                self.active_entity.setTarget(entity)
                return True
            # 如果select不为空
            elif self.select is not None:
                # 设置active_entity的目的地
                self.active_entity.setDestination(self.select[0], self.select[1], entity)
                return True
        return False

    def checkMouseMove(self, x, y):
        # 检查是否存在激活的实体
        if self.active_entity is None:
            # 如果激活的实体不存在，则返回False
            return False

        # 将鼠标位置的屏幕坐标转换为地图上的索引坐标
        map_x, map_y = self.getMapIndex(x, y)
        # 检查转换后的地图坐标是否有效
        if not self.isValid(map_x, map_y):
            # 如果坐标无效，则返回False
            return False

        # 初始化self.select为None
        self.select = None
        # 获取当前鼠标位置的实体对象
        entity = self.entity_map[map_y][map_x]
        # 检查当前实体是否可以移动，或者当前实体是否与激活的实体相同，并且激活的实体是否在攻击范围内
        if ((self.isMovable(map_x, map_y) or entity == self.active_entity) and
                self.active_entity.inRange(self, map_x, map_y)):
            # 如果上述条件都满足，则设置背景地图的该位置为c.BG_SELECT
            self.bg_map[map_y][map_x] = c.BG_SELECT
        elif entity is not None:
            # 如果当前位置有实体，且不是激活的实体，则继续处理
            if entity.group_id != self.active_entity.group_id:
                # 检查当前位置的实体是否属于激活实体的不同组
                if self.active_entity.isRemote():
                    # 如果激活实体是远程攻击类型，则设置背景地图的该位置为c.BG_ATTACK
                    self.bg_map[map_y][map_x] = c.BG_ATTACK
                else:
                    # 如果激活实体不是远程攻击类型，则执行以下步骤
                    dir_list = tool.getAttackPositions(map_x, map_y)
                    res_list = []
                    for offset_x, offset_y in dir_list:
                        # 遍历攻击方向列表
                        if self.isValid(map_x + offset_x, map_y + offset_y):
                            # 检查添加偏移量后的位置是否有效
                            type = self.bg_map[map_y + offset_y][map_x + offset_x]
                            # 检查添加偏移量后的位置是否可以攻击
                            if type == c.BG_RANGE or type == c.BG_ACTIVE:
                                # 如果可以攻击，则将该位置添加到res_list中
                                res_list.append((map_x + offset_x, map_y + offset_y))
                    # 如果res_list中有可攻击的位置，则继续处理
                    if len(res_list) > 0:
                        min_dis = c.MAP_WIDTH
                        for tmp_x, tmp_y in res_list:
                            # 遍历res_list中的每个可攻击位置
                            distance = self.getDistance(x, y, tmp_x, tmp_y)
                            # 计算鼠标位置与可攻击位置之间的距离
                            if distance < min_dis:
                                # 如果距离小于最小距离，则更新最小距离和目标位置
                                min_dis = distance
                                res = (tmp_x, tmp_y)
                        # 设置背景地图的最小距离位置为c.BG_SELECT
                        self.bg_map[res[1]][res[0]] = c.BG_SELECT
                        # 设置背景地图的当前位置为c.BG_ATTACK
                        self.bg_map[map_y][map_x] = c.BG_ATTACK
                        # 更新self.select为最小距离位置
                        self.select = res

    def setEntity(self, map_x, map_y, value):
        self.entity_map[map_y][map_x] = value

    def drawMouseShow(self, surface):
        # 获取鼠标的坐标
        x, y = pg.mouse.get_pos()
        # 获取鼠标所在地图的索引
        map_x, map_y = self.getMapIndex(x, y)
        # 判断鼠标所在地图索引是否有效
        if self.isValid(map_x, map_y):
            # 设置鼠标图片的位置
            self.mouse_rect.x = x
            self.mouse_rect.y = y
            # 将鼠标图片绘制到屏幕上
            surface.blit(self.mouse_image, self.mouse_rect)

    def updateMap(self):
        # 遍历地图每个位置
        for y in range(self.height):
            for x in range(self.width):
                # 将地图设置为空
                self.bg_map[y][x] = c.BG_EMPTY
                # 如果实体地图该位置不为空，且实体为死亡状态，则将实体地图该位置设置为空
                if self.entity_map[y][x] is not None and self.entity_map[y][x].isDead():
                    self.entity_map[y][x] = None

        # 如果活动实体为空或者活动实体状态不为空闲，则返回
        if self.active_entity is None or self.active_entity.state != c.IDLE:
            return
        # 获取活动实体地图坐标
        map_x, map_y = self.active_entity.map_x, self.active_entity.map_y
        # 将活动实体地图坐标设置为活动
        self.bg_map[map_y][map_x] = c.BG_ACTIVE

        # 遍历地图每个位置
        for y in range(self.height):
            for x in range(self.width):
                # 如果该位置不可移动或者不可达，则跳过
                if not self.isMovable(x,y) or not self.isValid(x,y):
                    continue
                # 如果活动实体在范围内，则将地图该位置设置为范围
                if self.active_entity.inRange(self, x, y):
                    self.bg_map[y][x] = c.BG_RANGE
        # 获取鼠标坐标
        mouse_x, mouse_y = pg.mouse.get_pos()
        # 检查鼠标移动
        self.checkMouseMove(mouse_x, mouse_y)

    def drawBackground(self, surface):
        # 如果地图是六边形
        if c.MAP_HEXAGON:
            # 绘制六边形地图
            return self.drawBackgroundHex(surface)

        # 绘制矩形地图
        pg.draw.rect(surface, c.LIGHTYELLOW, pg.Rect(0, 0, c.MAP_WIDTH, c.MAP_HEIGHT))

        # 遍历地图每个格子
        for y in range(self.height):
            for x in range(self.width):
                # 如果格子是空的
                if self.bg_map[y][x] == c.BG_EMPTY:
                    # 设置颜色为浅黄色
                    color = c.LIGHTYELLOW
                # 如果格子是激活的
                elif self.bg_map[y][x] == c.BG_ACTIVE:
                    # 设置颜色为天蓝色
                    color = c.SKY_BLUE
                # 如果格子是攻击范围
                elif self.bg_map[y][x] == c.BG_RANGE:
                    # 设置颜色为深蓝色
                    color = c.NAVYBLUE
                # 如果格子是选择的
                elif self.bg_map[y][x] == c.BG_SELECT:
                    # 设置颜色为绿色
                    color = c.GREEN
                # 如果格子是攻击的
                elif self.bg_map[y][x] == c.BG_ATTACK:
                    # 设置颜色为金色
                    color = c.GOLD
                # 绘制格子
                pg.draw.rect(surface, color, (x * c.REC_SIZE, y * c.REC_SIZE,
                        c.REC_SIZE, c.REC_SIZE))

        # 绘制地图图片
        surface.blit(self.map_image, self.rect)

        # 遍历地图每个格子
        for y in range(self.height):
            # 绘制水平线
            start_pos = (0, 0 + c.REC_SIZE * y)
            end_pos = (c.MAP_WIDTH, c.REC_SIZE * y)
            pg.draw.line(surface, c.BLACK, start_pos, end_pos, 1)

        for x in range(self.width):
            # 绘制垂直线
            start_pos = (c.REC_SIZE * x, 0) 
            end_pos = (c.REC_SIZE * x, c.MAP_HEIGHT)
            pg.draw.line(surface, c.BLACK, start_pos, end_pos, 1)

    def calHeuristicDistance(self, x1, y1, x2, y2):
        # 如果地图是六边形
        if c.MAP_HEXAGON:
            # 计算y轴距离
            dis_y = abs(y1 - y2)
            # 计算x轴距离
            dis_x = abs(x1 - x2)
            # 计算y轴距离的一半
            half_y = dis_y // 2
            # 如果y轴距离大于x轴距离
            if dis_y >= dis_x:
                # x轴距离置为0
                dis_x = 0
            else:
                # x轴距离减去y轴距离的一半
                dis_x -= half_y
            # 返回总距离
            return (dis_y + dis_x)
        else:
            # 返回x轴距离和y轴距离之和
            return abs(x1 - x2) + abs(y1 - y2)

    def drawBackgroundHex(self, surface):
        # 定义Y_LEN和X_LEN变量，用于存储Hex的Y和X方向上的长度
        Y_LEN = c.HEX_Y_SIZE // 2
        X_LEN = c.HEX_X_SIZE // 2

        # 使用pg.draw.rect函数绘制一个矩形，颜色为c.LIGHTYELLOW，位置为(0, 0, c.MAP_WIDTH, c.MAP_HEIGHT)
        pg.draw.rect(surface, c.LIGHTYELLOW, pg.Rect(0, 0, c.MAP_WIDTH, c.MAP_HEIGHT))

        # 使用两层循环遍历bg_map二维数组
        for y in range(self.height):
            for x in range(self.width):
                # 根据bg_map二维数组中的值，判断颜色
                if self.bg_map[y][x] == c.BG_EMPTY:
                    color = c.LIGHTYELLOW
                elif self.bg_map[y][x] == c.BG_ACTIVE:
                    color = c.SKY_BLUE
                elif self.bg_map[y][x] == c.BG_RANGE:
                    color = c.NAVYBLUE
                elif self.bg_map[y][x] == c.BG_SELECT:
                    color = c.GREEN
                elif self.bg_map[y][x] == c.BG_ATTACK:
                    color = c.GOLD

                # 获取Hex在地图上的位置
                base_x, base_y = tool.getHexMapPos(x, y)
                # 计算Hex的六个点的位置
                points = [(base_x, base_y + Y_LEN//2 + Y_LEN), (base_x, base_y + Y_LEN//2),
                          (base_x + X_LEN, base_y), (base_x + X_LEN * 2, base_y + Y_LEN//2),
                          (base_x + X_LEN * 2, base_y + Y_LEN//2 + Y_LEN), (base_x + X_LEN, base_y + Y_LEN*2)]
                # 使用pg.draw.polygon函数绘制Hex，颜色为color
                pg.draw.polygon(surface, color, points)

        # 将map_image绘制到surface上
        surface.blit(self.map_image, self.rect)

        # 使用两层循环遍历bg_map二维数组
        for y in range(self.height):
            for x in range(self.width):
                # 如果y为奇数，且x为最后一列，则跳过
                if y % 2 == 1 and x == self.width - 1:
                    continue
                # 获取Hex在地图上的位置
                base_x, base_y = tool.getHexMapPos(x, y)
                # 计算Hex的六个点的位置
                points = [(base_x, base_y + Y_LEN//2 + Y_LEN), (base_x, base_y + Y_LEN//2),
                          (base_x + X_LEN, base_y), (base_x + X_LEN * 2, base_y + Y_LEN//2),
                          (base_x + X_LEN * 2, base_y + Y_LEN//2 + Y_LEN), (base_x + X_LEN, base_y + Y_LEN*2)]
                # 使用pg.draw.lines函数绘制Hex的边框，颜色为c.BLACK
                pg.draw.lines(surface, c.BLACK, True, points)